package com.rabbiter.association.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.AlipayConstants;
import com.alipay.api.domain.*;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.*;
import com.alipay.api.response.*;
import com.rabbiter.association.config.AlipayClientConfig;
import com.rabbiter.association.enums.AilPayBillTypeEnum;
import com.rabbiter.association.msg.R;
import com.rabbiter.association.service.AliPayService;
import com.rabbiter.association.utils.QRcodeUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Map;


@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
@Slf4j
@Service
@RequiredArgsConstructor
public class AliPayServiceImpl implements AliPayService {


    private final AlipayClientConfig alipayClientConfig; // 支付宝客户端配置


    private final AlipayClient alipayClient; // 支付宝客户端

    @Override
    public String aliPayPreorder(String orderId) {
        log.info("订单号：{}", orderId);

        // 组装当前业务方法的请求参数
        JSONObject bizContent = new JSONObject();
        bizContent.put("out_trade_no", orderId); // 订单号
        bizContent.put("total_amount", "0.01"); // 总金额
        bizContent.put("subject", "支付测试"); // 使用订单标题
        bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY"); // 产品码，固定值

        // 调用支付宝接口
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
        request.setBizContent(bizContent.toString()); // 设置业务参数
        // 设置异步通知地址
        request.setNotifyUrl(alipayClientConfig.getNotifyUrl());
        // 设置同步通知地址
        //request.setReturnUrl(alipayClientConfig.getReturnUrl());

        try {
            //支付预下单
            AlipayTradePagePayResponse response = alipayClient.pageExecute(request);
            if (response.isSuccess()) {
                log.info("调用成功，响应内容：{}", response.getBody());
                return response.getBody(); // 返回支付宝生成的支付表单
            } else {
                log.error("调用失败，错误码：{}, 错误信息：{}", response.getSubCode(), response.getSubMsg());
                return null;
            }
        } catch (AlipayApiException e) {
            log.error("调用支付宝接口时发生异常", e);
            throw new RuntimeException("调用支付宝接口时发生异常", e);
        }
    }

    @Override
    public R getQrCode(String orderId) {
        log.info("订单号：{}", orderId);
        AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
        // 组装当前业务方法的请求参数
        JSONObject bizContent = new JSONObject();
        bizContent.put("out_trade_no", orderId); // 订单号
        bizContent.put("total_amount", "0.01"); // 总金额
        bizContent.put("subject", "支付测试"); // 使用订单标题
        /**
         * product_code 支付产品类型
         * QUICK_MSECURITY_PAY 适用于需要更高安全性的支付场景
         * QUICK_WAP_WAY 适用于手机网页支付场景
         * PRE_AUTH_ONLINE 适用于需要授权支付的场景
         * FACE_TO_FACE_PAYMENT 适用于当面付场景
         */
        bizContent.put("product_code", "FACE_TO_FACE_PAYMENT");
        request.setBizContent(bizContent.toString());
        // 设置同步通知地址
        request.setReturnUrl(alipayClientConfig.getReturnUrl());
        // 设置异步通知地址 实际开发推荐使用
        //request.setNotifyUrl(alipayClientConfig.getNotifyUrl());

        // 打印请求参数以便调试
        log.info("请求参数: {}", bizContent.toJSONString());

        try {
            AlipayTradePrecreateResponse response = alipayClient.execute(request);
            if (response.isSuccess()) {
                log.info("调用成功，响应内容：{}", response.getBody());
                return R.success("支付二维码获取成功", response.getQrCode());
            } else {
                log.error("调用失败，错误码：{}, 错误信息：{}", response.getSubCode(), response.getSubMsg());
            }
        } catch (AlipayApiException e) {
            log.error("调用支付宝接口时发生异常", e);
            throw new RuntimeException(e);
        }
        return R.error("调用支付宝接口时发生异常");
    }


    @Override
    public void getQrCodeImage(String orderId, HttpServletResponse response) {
        // 调用获取支付二维码内容接口
        R qrCodeResponse = this.getQrCode(orderId);
        // 获取二维码字符串
        String qrCodeContent = (String) qrCodeResponse.get("data");
        if (qrCodeContent == null) {
            log.error("获取二维码内容失败");
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }
        try {
            // 调用生成二维码的方法
            QRcodeUtils.createQRCode(qrCodeContent, response);
        } catch (Exception e) {
            log.error("生成二维码时发生异常", e);
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }
    }

    @Override
    public R aliPayNotify(Map<String, String> params) {
        log.info("支付回调正在执行");
        log.info("支付宝回调参数为===>{}", JSON.toJSONString(params));
        //验签
        boolean signVerified = false;
        try {
            // 入参
            signVerified = AlipaySignature.rsaCheckV1(params, alipayClientConfig.getAlipayPublicKey(), AlipayConstants.CHARSET_UTF8, AlipayConstants.SIGN_TYPE_RSA2);
            //验签成功
            if (signVerified) {
                log.info("验签成功");
                // 1.商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号  数据库查询这条记录是否存在？在生成订单的时候创建订单
                String out_trade_no = params.get("out_trade_no");
                // 根据订单号查询这条记录，返回order，如果不存在返回result(failure)

                // 2.商户需要验证该通知数据中的total_amount是否为该订单的实际金额(即商户订单创建时的金额)
                String totalAmount = params.get("total_amount");
                int totalAmountInt = new BigDecimal(totalAmount).multiply(new BigDecimal("100")).intValue();
                // 将order中的价格拿出来跟这个作比较，若不同返回result(failure)

                // 3. 校验通知中的seller_id(或者sell_email)是否为out_trade_no 这笔单据的对应的操作方法  需要保持与商户pid一致
                String sellerId = params.get("seller_id");
                if (!sellerId.equals(alipayClientConfig.getSellerPid())) {
                    log.error("商家pid校验失败");
                    return R.error("商家pid校验失败");
                }

                // 4. 验证app_id 是否为商户本身
                String appId = params.get("app_id");
                if (!appId.equals(alipayClientConfig.getAppId())) {
                    log.error("appId校验失败");
                    return R.error("appId校验失败");
                }

                /**
                 * trade_status 表示交易的当前状态
                 * WAIT_BUYER_PAY: 交易创建，等待买家付款。
                 * TRADE_CLOSED: 未付款交易超时关闭，或支付完成后全额退款。
                 * TRADE_SUCCESS: 交易成功，且可对该交易做操作，如退款。
                 * TRADE_FINISHED: 交易成功且结束，不可再做操作，如退款
                 */
                // 5. 验证交易通知是否为TRADE_SUCCESS,只有为TRADE_SUCCESS支付宝才会认定买家付款成功
                String tradeStatus = params.get("trade_status");
                if (!"TRADE_SUCCESS".equals(tradeStatus)) {
                    log.error("支付未成功");
                    return R.error("支付未成功");
                }

                // 处理订单后续
                log.info("5大校验验证通过,开始对回调函数进行处理");
                // TODO 进行自己的业务操作
                return R.successMsg("支付成功");
            } else {
                log.error("验签失败");
                return R.error("验签失败");
            }
        } catch (AlipayApiException e) {
            log.error("验签异常");
            return R.error("验签异常");
        }
    }

    @Override
    public R queryAliPayOrder(String orderId) {
        //请求
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        //数据
        AlipayTradeQueryModel bizModel = new AlipayTradeQueryModel();
        bizModel.setOutTradeNo(orderId);
        request.setBizModel(bizModel);
        try {
            //完成签名并执行请求
            AlipayTradeQueryResponse response = alipayClient.execute(request);
            if (response.isSuccess()) {
                log.info("查询订单{}成功", orderId);
                return R.success(response.getMsg(), response.getBody());
            } else {
                log.error("查询订单{}失败,响应数据是{}.", orderId, response.getBody());
                return R.error("查询订单失败");
            }
        } catch (AlipayApiException e) {
            log.error("查询订单{}异常", orderId);
            return R.error("查询订单异常");
        }
    }

    @Override
    public R aliPayRefund(Map<String, String> params) {
        //订单号
        String outTradeNo = params.get("out_trade_no");
        //请求
        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
        //数据
        AlipayTradeRefundModel bizModel = new AlipayTradeRefundModel();
        //订单号
        bizModel.setOutTradeNo(outTradeNo);
        // 退款金额
        bizModel.setRefundAmount("0.01");
        //退款原因
        bizModel.setRefundReason(params.get("refund_reason"));
        request.setBizModel(bizModel);
        log.info("签名入参===>{}", JSON.toJSONString(request));
        try {
            //完成签名并执行请求
            AlipayTradeRefundResponse response = alipayClient.execute(request);
            //成功则说明退款成功了
            if (response.isSuccess()) {
                log.info("订单{}退款成功", outTradeNo);
                return R.success(response.getMsg(), response.getBody());
            } else {
                log.error("订单{}退款失败，错误原因===>{}", outTradeNo, response.getSubMsg());
                throw new RuntimeException("订单退款失败");
            }
        } catch (AlipayApiException e) {
            log.error("订单{}退款异常", outTradeNo);
            throw new RuntimeException("订单退款异常");
        }

    }

    @Override
    public R aliPayRefundQuery(String orderId) {
        AlipayTradeFastpayRefundQueryRequest request = new AlipayTradeFastpayRefundQueryRequest();
        AlipayTradeFastpayRefundQueryModel bizModel = new AlipayTradeFastpayRefundQueryModel();
        //订单号
        bizModel.setOutTradeNo(orderId);
        // 退款订单号,如果退款时候没有传退款订单号，那么查询时就传订单号
        bizModel.setOutRequestNo(orderId);
        //想要额外返回的数据(也就是文档中响应可选的数据)
        ArrayList<String> extraResponseDatas = new ArrayList<>();
        extraResponseDatas.add("refund_status");
        bizModel.setQueryOptions(extraResponseDatas);
        request.setBizModel(bizModel);
        try {
            //完成签名并执行请求
            AlipayTradeFastpayRefundQueryResponse response = alipayClient.execute(request);
            if (response.isSuccess()) {
                log.info("退款{}查询成功", orderId);
                return R.successData(response.getBody());
            } else {
                log.debug("退款{}查询失败,原因是==>{}", orderId, response.getSubMsg());
                return null;
            }
        } catch (AlipayApiException e) {
            log.debug("退款{}查询异常", orderId);
            return null;
        }
    }

    @Override
    public R getAliPayBill(String billDate, String type) {
        // 请求
        AlipayDataDataserviceBillDownloadurlQueryRequest request = new AlipayDataDataserviceBillDownloadurlQueryRequest();
        // 数据
        AlipayDataDataserviceBillDownloadurlQueryModel bizModel = new AlipayDataDataserviceBillDownloadurlQueryModel();

        // 使用枚举类设置 billType
        try {
            AilPayBillTypeEnum billType = AilPayBillTypeEnum.fromCode(type);
            bizModel.setBillType(billType.getCode());
        } catch (IllegalArgumentException e) {
            log.error("无效的账单类型: {}", type);
            return R.error("无效的账单类型");
        }

        bizModel.setBillDate(billDate);
        request.setBizModel(bizModel);

        try {
            // 完成签名并执行请求
            AlipayDataDataserviceBillDownloadurlQueryResponse response = alipayClient.execute(request);
            if (response.isSuccess()) {
                log.info("获取账单下载url成功");
                return R.successData(response.getBillDownloadUrl());
            } else {
                log.error("获取账单下载url失败,原因是===>{}", response.getSubMsg());
                return R.error(response.getSubMsg());
            }
        } catch (AlipayApiException e) {
            log.error("获取账单下载url异常", e);
            return R.error("获取账单下载url异常");
        }
    }


    @Override
    public R cancelAliPayOrder(String orderId) {
        log.info("关单接口的订单号,订单号===>{}", JSON.toJSONString(orderId));
        //请求
        AlipayTradeCloseRequest request = new AlipayTradeCloseRequest();
        //数据
        AlipayTradeCloseModel bizModel = new AlipayTradeCloseModel();
        bizModel.setOutTradeNo(orderId);
        request.setBizModel(bizModel);
        try {
            //完成签名并执行请求
            AlipayTradeCloseResponse response = alipayClient.execute(request);
            if (response.isSuccess()) {
                log.info("订单{}取消成功", orderId);
                return R.success(response.getMsg(), response.getBody());
            } else {
                log.info("订单{}取消失败,原因==>{}", orderId, response.getSubMsg());
                throw new RuntimeException("关单接口调用失败");
            }
        } catch (AlipayApiException e) {
            log.error("订单{}取消异常", orderId);
            throw new RuntimeException("关单接口异常");
        }
    }
}
